<?php
require_once "lib/conexao.php";

abstract class GenericDAO {
	protected $tabela;
	
	public function consultarPK($valor) {}
	public function inserir($registro, $finalizarTransacao) {}
	public function excluir($registro, $finalizarTransacao) {}
	public function alterar($registro, $finalizarTransacao) {}
	
	public function commit() {
		$con = Conexao::getConexao();
		if ($con->inTransaction()) {
			$con->commit();
		}
	}
	
	public function rollback() {
		$con = Conexao::getConexao();
		if ($con->inTransaction()) {
			$con->rollBack();
		}
	}
	
	public function ultimoId() {
		$sql = "select last_insert_id() id from " . $this->tabela["alteracao"]["nome"];
		$res = $this->execQuery($sql, null);
		return isset($res[0]["id"]) ? $res[0]["id"] : null;
	}
	
	protected function addRecursoSelfPerm($dataSet, $fldRecursoId = 'id') {
		foreach($dataSet as $key => $rec) {
			if (isset($dataSet[$key]["acesso"])) {
				$dataSet[$key]["acesso"] = ($dataSet[$key]["acesso"] == 1);
			}
			$dataSet[$key]["selfPerm"] = (bool) $this->consultarPermissao($_SESSION["usuario"]["id"], $rec[$fldRecursoId]);
		}
		return $dataSet;
	}
	
	protected function addGrupoSelfPerm($dataSet, $fldGrupoId = 'id') {
		foreach($dataSet as $key => $grp) {
			$sql = "select grupo from usu_x_grupo where usuario = :usuario";
			$params["usuario"] = $_SESSION["usuario"]["id"];
			$grpsUsu = $this->execQuery($sql, $params);
			foreach($grpsUsu as $grpUsu) { 
				$dataSet[$key]["grpSelfPerm"] = ($grpUsu['grupo'] == $grp[$fldGrupoId]) || ($this->ehFilho($grpUsu['grupo'], $grp[$fldGrupoId]) > 0);
			}
		}
		return $dataSet;
	}
	
	protected function ehFilho($pai, $filho, $pk, $fk) {
		/* Verifica o parentesco entre $pai e $filho.
		 * Retorno:
		 * 		 1: caso $pai seja ascendente de $filho
		 * 		 0: caso não haja relação de parentesco
		 * 		-1: caso $filho seja ascendente de $pai
		 */
		$res = 0;
		$ptr = $filho;
		$sql = "select $pk from " . $this->tabela["alteracao"]["nome"] . "where $pk = :pk";
		do {
			$params["pk"] = $ptr;
			$aux = $this->execQuery($sql, $params);
			$res = ($aux[$fk] == $pai) ? 1 : 0;
			$ptr = $aux[$fk];
		} while (!$res && !is_null($ptr));

		$ptr = $pai;
		while (!res && !is_null($ptr)) {
			$params["pk"] = $ptr;
			$aux = $this->execQuery($sql, $params);
			$res = ($aux[$fk] == $filho) ? -1 : 0;
			$ptr = $aux[$fk];
		}
		
		return $res;
	}
	
	protected function execQuery($sql, $params) {  
		$con = Conexao::getConexao();
		
		$comando = $con->prepare($sql);
		
		if (!$comando->execute($params)) {
			$erro = $comando->errorInfo();
			throw new Exception(print_r($erro, true));
		}
		
		return $comando->fetchAll(PDO::FETCH_ASSOC);
	}
	
	public function consultar($where, $params, $orderLimit = "") {
		return $this->execQuery($this->getSelectSQL() . " $where $orderLimit", $params); 
	}
	
	public function contarRegistros($where, $params) {
		$this->consultarPermissao($_SESSION["usuario"]["id"], $this->tabela["consulta"]["id"], true);
		
		$sql = "select count(*) qtd from " . $this->tabela["consulta"]["nome"] . " $where";
		$res = $this->execQuery($sql, $params);
		return (isset($res[0])) ? $res[0]["qtd"] : 0;
	}
	
	protected function execSQL($sql, $params, $finalizarTransacao = true) {
		try {
		    $con = Conexao::getConexao();
			if (!$con->inTransaction()) {
				$con->beginTransaction();
			}
	
			$comando = $con->prepare($sql);
			if (!$comando) {
				throw new Exception("O comando $sql não pode ser preparado." . print_r($con->errorInfo(), true));
			}
			
			$rwn 	 = $comando->execute($params);
			if (!$rwn) {
				$erro = $comando->errorInfo();
				$erro['sql'] = $sql;
				$erro['params'] = $params;
				throw new Exception(print_r($erro, true));
			}
	
			if ($con->inTransaction() && $finalizarTransacao) {
				$con->commit();
			}
			return true;
		} catch (Exception $e) {
			if ($con->inTransaction()) {
				$con->rollBack();
			}
			throw new Exception($e);
		}
	}
	
	private function getSelectSQL() {
		$this->consultarPermissao($_SESSION["usuario"]["id"], $this->tabela["consulta"]["id"], true);

		$sql = "select ";
		$sqlFilhos = "select id,		" . 
					 "       nome		" .
					 "  from recurso 	" .
					 " where recurso = :recurso";
		
		$params["recurso"] = $this->tabela["consulta"]["id"];
		$campos = array();
		
		$recs = $this->execQuery($sqlFilhos, $params);
		foreach($recs as $recurso) {
			if (!$this->consultarPermissao($_SESSION["usuario"]["id"], $recurso["id"])) {
				$campos[] = '"###" ' . $recurso["nome"];
			} else {
				$campos[] = $recurso["nome"];
			}
		}
		$sql .= implode(", ", $campos);
		$sql .=	" from "  . $this->tabela["consulta"]["nome"];
		return $sql;
	}
	
	public function consultarPermissao($usuario, $recurso, $lancaExcpetion = false) {
		if (!isset($_SESSION["acesso"][$recurso])) {
			$sqlPermissao = "select max(acesso) acesso 					" .
							"  from acesso 								" .
							" where grupo in (select grupo 				" .
							"					from usu_x_grupo 		" .
							"				   where usuario = :usuario)" .
							"	and recurso = :recurso 					" ;
			
			$sqlDependencias =  "select ido 			" .
								"  from rec_er			" .
								" where ente = :recurso	" ;

			$params = array("usuario" => $usuario,
							"recurso" => $recurso);
			
			$aux = $this->execQuery($sqlPermissao, $params);
			$_SESSION["acesso"][$recurso] = $aux[0]["acesso"];
	
			unset($params["usuario"]);
			$aux = $this->execQuery($sqlDependencias, $params);
			foreach($aux as $dep) {
				$_SESSION["acesso"][$recurso] = ($_SESSION["acesso"][$recurso] && $this->consultarPermissao($usuario, $dep['ido']));
			}
		}
		if ($lancaExcpetion && !$_SESSION["acesso"][$recurso]) {
			throw new Exception("Acesso não permitido ao recurso ($recurso).");
		}
		return $_SESSION["acesso"][$recurso];
	}
	
	protected function inserirRegistro($registro, $finalizarTransacao = true) {
		$listaCampos = implode(',', array_keys($registro));
		$listaParams = ":" . implode(', :', array_keys($registro));
				
		$this->consultarPermissao($_SESSION["usuario"]["id"], $this->tabela["alteracao"]["id"], true);
	
		$sql = "insert into " . $this->tabela["alteracao"]["nome"] . " ($listaCampos) values ($listaParams)";
		$this->execSQL($sql, $registro, $finalizarTransacao);
		return true;
	}
	
	protected function alterarRegistro($registro, $pk, $finalizarTransacao = true) {
		$sql = "update " . $this->tabela["alteracao"]["nome"];
		$cola = " set ";
		foreach(array_keys($registro) as $campo) {
			$sql .= "$cola $campo = :$campo";
			$cola = ','; 
		}
		$cola = " where ";
		foreach(array_keys($pk) as $campo) {
			$sql .= "$cola $campo = :$campo";
			$cola = ' and '; 
		}
		
		$this->consultarPermissao($_SESSION["usuario"]["id"], $this->tabela["alteracao"]["id"], true);
		
		return $this->execSQL($sql, array_merge($registro, $pk), $finalizarTransacao);
	}
	
	protected function excluirRegistro($pk, $finalizarTransacao = true) {
		$sql = "delete from " . $this->tabela["alteracao"]["nome"];
		$cola = " where";
		foreach(array_keys($pk) as $campo) {
			$sql .= "$cola $campo = :$campo";
			$cola = " and";
		}
		
		$this->consultarPermissao($_SESSION["usuario"]["id"], $this->tabela["alteracao"]["id"], true);
		
		return $this->execSQL($sql, $pk, $finalizarTransacao);
	}
}
?>